home *** CD-ROM | disk | FTP | other *** search
- /*
- * DL1 Quantization
- * ================
- *
- * File: dl1quant.c
- * Author: Dennis Lee E-mail: denlee@ecf.utoronto.ca
- *
- * Copyright (C) 1993-1997 Dennis Lee
- *
- * C implementation of DL1 Quantization.
- * DL1 Quantization is a 2-pass color quantizer optimized for speed.
- * The method was designed around the steps required by a 2-pass
- * quantizer and constructing a model that would require the least
- * amount of extra work. The resulting method is extremely fast --
- * about half the speed of a memcpy. That should make DL1 Quant the
- * fastest 2-pass color quantizer.
- *
- * This quantizer's quality is also among the best, slightly
- * better than Wan et al's marginal variance based quantizer. For
- * more on DL1 Quant's performance and other related information,
- * see DLQUANT.TXT included in this distribution.
- *
- *
- * NOTES
- * =====
- *
- * The dithering code is based on code from the IJG's jpeg library.
- *
- * This source code may be freely copied, modified, and redistributed,
- * provided this copyright notice is attached.
- * Compiled versions of this code, modified or not, are free for
- * personal use. Compiled versions used in distributed software
- * is also free, but a notification must be sent to the author.
- * An e-mail to denlee@ecf.utoronto.ca will do.
- *
- */
-
-
- /*
- * dl1quant.c
- *
- * Modified 27 Jun 1998
- * by Jarno van der Linden
- * jarno@kcbbs.gen.nz
- *
- * Some minor additions and changes to work with AmigaMesaRTL
- *
- * Version 1.1 02 Aug 1998
- * by Jarno van der Linden
- * jarno@kcbbs.gen.nz
- *
- * - Changed to a quantizer plugin library
- *
- */
-
-
- #define DL1SRC
-
- #include <stdlib.h>
- #include <string.h>
- #include "dl1quant.h"
-
- #include <intuition/intuition.h>
- #include <proto/intuition.h>
- #include <proto/graphics.h>
- #include <proto/utility.h>
-
- #include "gl/quantizer.h"
-
-
- /********** The following are options **********/
-
- //#define FAST /* improves speed but uses a lot of memory */
- //#define QUAL1 /* improves quality slightly (slower) */
- //#define QUAL2 /* improves quality slightly (slower) */
-
- /* define *one* of the following dither options */
- #define DITHER1 /* 1-val error diffusion dither */
- //#define DITHER2 /* 2-val error diffusion dither */
- //#define DITHER4 /* 4-val error diffusion dither (Floyd-Steinberg) */
-
- /********** End of options **********/
-
- #define DITHER_MAX 20
-
- LOCAL uchar palette[3][256];
- LOCAL CUBE *rgb_table[6];
- LOCAL ushort r_offset[256], g_offset[256], b_offset[256];
- LOCAL CLOSEST_INFO c_info;
- LOCAL int tot_colors, pal_index, did_init = 0;
- LOCAL ulong *squares;
- LOCAL FCUBE *heap = NULL;
- LOCAL short *dl_image = NULL;
-
- LOCAL int bufwidth,bufheight;
-
- struct dl1Context {
- struct Window *window;
- int mode;
- struct DrawInfo *di;
- struct BitMap bm;
- struct RastPort rp;
- UBYTE *qbuffer;
- ULONG *palette;
- ULONG numc, firstc;
- int rw, rh;
- int ww, wh;
- };
-
-
- struct dl1Context context;
-
- #define WINWIDTH(w) ((w)->Width - (w)->BorderLeft - (w)->BorderRight)
- #define WINHEIGHT(w) ((w)->Height - (w)->BorderTop - (w)->BorderBottom)
-
- BOOL InitWritePixelA8(void)
- {
- int depth;
-
- InitBitMap(&(context.bm), context.di->dri_Depth, context.rw, 1);
-
- for(depth=0; depth<context.di->dri_Depth; depth++)
- {
- context.bm.Planes[depth] = (PLANEPTR)AllocRaster(context.rw, 1);
- if(!context.bm.Planes[depth])
- return FALSE;
- }
-
- context.rp = *(context.window->RPort);
- context.rp.Layer = NULL;
- context.rp.BitMap = &(context.bm);
-
- return(TRUE);
- }
-
-
- void DelWritePixelA8(void)
- {
- int depth;
-
- for(depth=0; depth<context.di->dri_Depth; depth++)
- {
- if(context.bm.Planes[depth]) FreeRaster(context.bm.Planes[depth], context.rw, 1);
- context.bm.Planes[depth] = NULL;
- }
- }
-
-
- __asm __saveds int InitQuantizer(register __a0 struct Window *window, register __d0 ULONG mode, register __d1 ULONG numcolours, register __d2 ULONG firstcolour)
- {
- int depth;
-
- context.window = window;
- context.mode = mode;
- context.di = GetScreenDrawInfo(window->WScreen);
- context.qbuffer = NULL;
-
- for(depth=0; depth<context.di->dri_Depth; depth++)
- {
- context.bm.Planes[depth] = NULL;
- }
-
- if(mode == AMRTL_RGBAMode)
- {
- context.numc = numcolours;
- context.firstc = firstcolour;
- context.palette = calloc(1+context.numc*3+1,sizeof(ULONG));
- }
-
- dlq_init();
- dlq_start();
- return 1;
- }
-
-
- __asm __saveds void DeleteQuantizer(void)
- {
- dlq_finish();
-
- DelWritePixelA8();
-
- if(context.palette) free(context.palette);
- context.palette = NULL;
-
- if(context.di) FreeScreenDrawInfo(context.window->WScreen, context.di);
- context.di = NULL;
-
- if(context.qbuffer) free(context.qbuffer);
- context.qbuffer = NULL;
- }
-
-
- __asm __saveds int ResizeQuantizer(register __d0 int width, register __d1 int height)
- {
- DelWritePixelA8();
- if(context.qbuffer) free(context.qbuffer);
- context.qbuffer = NULL;
-
- bufwidth = width;
- bufheight = height;
- #ifdef FAST
- if(dl_image) free(dl_image)
- dl_image = malloc(sizeof(short) * width*height);
- #endif
-
- context.rw = width;
- context.rh = height;
-
- context.ww = WINWIDTH(context.window);
- context.wh = WINHEIGHT(context.window);
-
- if(context.mode == AMRTL_RGBAMode)
- context.qbuffer = (UBYTE *)calloc(context.rw * context.rh, sizeof(UBYTE));
-
- InitWritePixelA8();
- return 1;
- }
-
-
- void dl1Quantize(unsigned long *buffer, unsigned long numc, unsigned long base, unsigned char *qbuffer,unsigned long *paltable);
- __asm __saveds int Quantize(register __a0 APTR buffer)
- {
- if(context.mode == AMRTL_RGBAMode)
- {
- dl1Quantize((ULONG *)buffer, context.numc, context.firstc, context.qbuffer, context.palette);
- LoadRGB32(ViewPortAddress(context.window), context.palette);
-
- if((WINWIDTH(context.window) != context.ww) || (WINHEIGHT(context.window) != context.wh))
- return 1;
- WritePixelArray8(context.window->RPort,
- context.window->BorderLeft , context.window->BorderTop,
- context.window->BorderLeft + context.ww-1, context.window->BorderTop + context.wh-1,
- context.qbuffer, &(context.rp));
- }
- else if(context.mode == AMRTL_IndexMode)
- {
- WritePixelArray8(context.window->RPort,
- context.window->BorderLeft , context.window->BorderTop,
- context.window->BorderLeft + context.ww-1, context.window->BorderTop + context.wh-1,
- buffer, &(context.rp));
- }
- return 1;
- }
-
-
- void dl1Quantize(unsigned long *buffer, unsigned long numc, unsigned long base, unsigned char *qbuffer,unsigned long *paltable)
- {
- unsigned long *pp;
- unsigned char *pr,*pg,*pb;
- int t;
-
- reset();
- build_table(buffer, (ulong)bufwidth * (ulong)bufheight);
- reduce_table(numc);
- set_palette(0, 0);
- quantize_image(buffer, qbuffer, bufwidth, bufheight, 1, base);
-
- pp = paltable;
- pr = palette[0];
- pg = palette[1];
- pb = palette[2];
-
- *pp++ = (numc<<16)+base;
-
- for(t=0; t<numc; t++)
- {
- *pp++ = ((unsigned long)(*pr++)) * 0x01010101;
- *pp++ = ((unsigned long)(*pg++)) * 0x01010101;
- *pp++ = ((unsigned long)(*pb++)) * 0x01010101;
- }
- *pp = 0;
- }
-
-
- #if 0
- /* returns 1 on success, 0 on failure */
- GLOBAL int
- dl1quant(uchar *inbuf, uchar *outbuf, int width, int height, int quant_to,
- int dither, uchar userpal[3][256]) {
-
- if (!did_init) {
- did_init = 1;
- dlq_init();
- }
- if (dlq_start() == 0) {
- dlq_finish();
- return 0;
- }
- if (build_table(inbuf, (ulong)width * (ulong)height) == 0) {
- dlq_finish();
- return 0;
- }
- reduce_table(quant_to);
- set_palette(0, 0);
- if (quantize_image(inbuf, outbuf, width, height, dither) == 0) {
- dlq_finish();
- return 0;
- }
- dlq_finish();
- copy_pal(userpal);
-
- return 1;
- }
- #endif
-
- LOCAL void
- copy_pal(uchar userpal[3][256]) {
- int i;
-
- for (i = 0; i < 256; i++) {
- userpal[0][i] = palette[0][i];
- userpal[1][i] = palette[1][i];
- userpal[2][i] = palette[2][i];
- }
- }
-
- LOCAL void
- dlq_init(void) {
- int i;
-
- for (i = 0; i < 256; i++) {
- r_offset[i] = (i & 128) << 7 | (i & 64) << 5 | (i & 32) << 3 |
- (i & 16) << 1 | (i & 8) >> 1;
- g_offset[i] = (i & 128) << 6 | (i & 64) << 4 | (i & 32) << 2 |
- (i & 16) << 0 | (i & 8) >> 2;
- b_offset[i] = (i & 128) << 5 | (i & 64) << 3 | (i & 32) << 1 |
- (i & 16) >> 1 | (i & 8) >> 3;
- }
-
- for (i = (-255); i <= 255; i++)
- c_info.squares[i+255] = i*i;
- squares = c_info.squares + 255;
- }
-
- /* returns 1 on success, 0 on failure */
- LOCAL int
- dlq_start(void) {
- int i;
-
- rgb_table[0] = (CUBE *) calloc(sizeof(CUBE), 1);
- rgb_table[1] = (CUBE *) calloc(sizeof(CUBE), 8);
- rgb_table[2] = (CUBE *) calloc(sizeof(CUBE), 64);
- rgb_table[3] = (CUBE *) calloc(sizeof(CUBE), 512);
- rgb_table[4] = (CUBE *) calloc(sizeof(CUBE), 4096);
- rgb_table[5] = (CUBE *) calloc(sizeof(CUBE), 32768);
-
- for (i = 0; i <= 5; i++)
- if (rgb_table[i] == NULL)
- return 0;
-
- pal_index = 0;
-
- heap = (FCUBE *) malloc(sizeof(FCUBE) * 32769);
- if(heap == NULL)
- return 0;
-
- return 1;
- }
-
-
- LOCAL void
- reset(void) {
- memset(rgb_table[0], 0, 1*sizeof(CUBE));
- memset(rgb_table[1], 0, 8*sizeof(CUBE));
- memset(rgb_table[2], 0, 64*sizeof(CUBE));
- memset(rgb_table[3], 0, 512*sizeof(CUBE));
- memset(rgb_table[4], 0, 4096*sizeof(CUBE));
- memset(rgb_table[5], 0, 32768*sizeof(CUBE));
-
- pal_index = 0;
- }
-
-
-
- LOCAL void
- dlq_finish(void) {
- if (rgb_table[0] != NULL)
- free(rgb_table[0]);
- if (rgb_table[1] != NULL)
- free(rgb_table[1]);
- if (rgb_table[2] != NULL)
- free(rgb_table[2]);
- if (rgb_table[3] != NULL)
- free(rgb_table[3]);
- if (rgb_table[4] != NULL)
- free(rgb_table[4]);
- if (rgb_table[5] != NULL)
- free(rgb_table[5]);
- if (heap != NULL)
- free(heap);
- if (dl_image != NULL)
- free(dl_image);
- }
-
- /* returns 1 on success, 0 on failure */
- LOCAL int
- build_table(uchar *image, ulong pixels) {
- ulong i, index, cur_count, head, tail;
- slong j;
-
- for (i = 0; i < pixels; i++) {
- #ifdef FAST
- dl_image[i] = index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
- #else
- index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
- #endif
- #ifdef QUAL1
- rgb_table[5][index].r += image[0];
- rgb_table[5][index].g += image[1];
- rgb_table[5][index].b += image[2];
- #endif
- rgb_table[5][index].pixel_count++;
- image += 4;
- }
-
- tot_colors = 0;
- for (i = 0; i < 32768; i++) {
- cur_count = rgb_table[5][i].pixel_count;
- if (cur_count) {
- heap[++tot_colors].level = 5;
- heap[tot_colors].index = i;
- rgb_table[5][i].pixels_in_cube = cur_count;
- #ifndef QUAL1
- rgb_table[5][i].r = cur_count * (((i & 0x4000) >> 7 |
- (i & 0x0800) >> 5 | (i & 0x0100) >> 3 |
- (i & 0x0020) >> 1 | (i & 0x0004) << 1) + 4);
- rgb_table[5][i].g = cur_count * (((i & 0x2000) >> 6 |
- (i & 0x0400) >> 4 | (i & 0x0080) >> 2 |
- (i & 0x0010) >> 0 | (i & 0x0002) << 2) + 4);
- rgb_table[5][i].b = cur_count * (((i & 0x1000) >> 5 |
- (i & 0x0200) >> 3 | (i & 0x0040) >> 1 |
- (i & 0x0008) << 1 | (i & 0x0001) << 3) + 4);
- #endif
- head = i;
- for (j = 4; j >= 0; j--) {
- tail = head & 0x7;
- head >>= 3;
- rgb_table[j][head].pixels_in_cube += cur_count;
- rgb_table[j][head].children |= 1 << tail;
- }
- }
- }
-
- for (i = tot_colors; i > 0; i--)
- fixheap(i);
-
- return 1;
- }
-
- LOCAL void
- fixheap(ulong id) {
- uchar thres_level = heap[id].level;
- ulong thres_index = heap[id].index, index, half_totc = tot_colors >> 1,
- thres_val = rgb_table[thres_level][thres_index].pixels_in_cube;
-
- while (id <= half_totc) {
- index = id << 1;
-
- if (index < tot_colors)
- if (rgb_table[heap[index].level][heap[index].index].pixels_in_cube
- > rgb_table[heap[index+1].level][heap[index+1].index].pixels_in_cube)
- index++;
-
- if (thres_val <= rgb_table[heap[index].level][heap[index].index].pixels_in_cube)
- break;
- else {
- heap[id] = heap[index];
- id = index;
- }
- }
- heap[id].level = thres_level;
- heap[id].index = thres_index;
- }
-
- LOCAL void
- reduce_table(int num_colors) {
- while (tot_colors > num_colors) {
-
- uchar tmp_level = heap[1].level, t_level = tmp_level - 1;
- ulong tmp_index = heap[1].index, t_index = tmp_index >> 3;
-
- if (rgb_table[t_level][t_index].pixel_count)
- heap[1] = heap[tot_colors--];
- else {
- heap[1].level = t_level;
- heap[1].index = t_index;
- }
- rgb_table[t_level][t_index].pixel_count += rgb_table[tmp_level][tmp_index].pixel_count;
- rgb_table[t_level][t_index].r += rgb_table[tmp_level][tmp_index].r;
- rgb_table[t_level][t_index].g += rgb_table[tmp_level][tmp_index].g;
- rgb_table[t_level][t_index].b += rgb_table[tmp_level][tmp_index].b;
- rgb_table[t_level][t_index].children &= ~(1 << (tmp_index & 0x7));
- fixheap(1);
- }
- }
-
- LOCAL void
- set_palette(int index, int level) {
- int i;
-
- if (rgb_table[level][index].children)
- for (i = 7; i >= 0; i--)
- if (rgb_table[level][index].children & (1 << i))
- set_palette((index << 3) + i, level + 1);
-
- if (rgb_table[level][index].pixel_count) {
- ulong r_sum, g_sum, b_sum, sum;
-
- rgb_table[level][index].palette_index = pal_index;
- r_sum = rgb_table[level][index].r;
- g_sum = rgb_table[level][index].g;
- b_sum = rgb_table[level][index].b;
- sum = rgb_table[level][index].pixel_count;
- palette[0][pal_index] = (r_sum + (sum >> 1)) / sum;
- palette[1][pal_index] = (g_sum + (sum >> 1)) / sum;
- palette[2][pal_index] = (b_sum + (sum >> 1)) / sum;
- pal_index++;
- }
- }
-
- LOCAL void
- closest_color(int index, int level) {
- int i;
-
- if (rgb_table[level][index].children)
- for (i = 7; i >= 0; i--)
- if (rgb_table[level][index].children & (1 << i))
- closest_color((index << 3) + i, level + 1);
-
- if (rgb_table[level][index].pixel_count) {
- slong dist, r_dist, g_dist, b_dist;
- uchar pal_num = rgb_table[level][index].palette_index;
-
- /* Determine if this color is "closest". */
- r_dist = palette[0][pal_num] - c_info.red;
- g_dist = palette[1][pal_num] - c_info.green;
- b_dist = palette[2][pal_num] - c_info.blue;
- dist = squares[r_dist] + squares[g_dist] + squares[b_dist];
- if (dist < c_info.distance) {
- c_info.distance = dist;
- c_info.palette_index = pal_num;
- }
- }
- }
-
- /* returns 1 on success, 0 on failure */
- LOCAL int
- quantize_image(uchar *in, uchar *out, int width, int height, int dither, int base) {
- if (!dither) {
- ulong i, pixels = width * height;
- ushort level, index;
- uchar tmp_r, tmp_g, tmp_b, cube, *lookup;
-
- lookup = malloc(sizeof(char) * 32768);
- if (lookup == NULL)
- return 0;
-
- for (i = 0; i < 32768; i++)
- if (rgb_table[5][i].pixel_count) {
- tmp_r = (i & 0x4000) >> 7 | (i & 0x0800) >> 5 |
- (i & 0x0100) >> 3 | (i & 0x0020) >> 1 |
- (i & 0x0004) << 1;
- tmp_g = (i & 0x2000) >> 6 | (i & 0x0400) >> 4 |
- (i & 0x0080) >> 2 | (i & 0x0010) >> 0 |
- (i & 0x0002) << 2;
- tmp_b = (i & 0x1000) >> 5 | (i & 0x0200) >> 3 |
- (i & 0x0040) >> 1 | (i & 0x0008) << 1 |
- (i & 0x0001) << 3;
- #ifdef QUAL2
- lookup[i] = bestcolor(tmp_r, tmp_g, tmp_b);
- #else
- c_info.red = tmp_r + 4;
- c_info.green = tmp_g + 4;
- c_info.blue = tmp_b + 4;
- level = 0;
- index = 0;
- for (;;) {
- cube = (tmp_r&128) >> 5 | (tmp_g&128) >> 6 | (tmp_b&128) >> 7;
- if ((rgb_table[level][index].children & (1 << cube)) == 0) {
- c_info.distance = ~0L;
- closest_color(index, level);
- lookup[i] = c_info.palette_index;
- break;
- }
- level++;
- index = (index << 3) + cube;
- tmp_r <<= 1;
- tmp_g <<= 1;
- tmp_b <<= 1;
- }
- #endif
- }
-
- for (i = 0; i < pixels; i++) {
- #ifdef FAST
- out[i] = lookup[dl_image[i]]+base;
- #else
- out[i] = lookup[r_offset[in[0]] + g_offset[in[1]] + b_offset[in[2]]]+base;
- in += 4;
- #endif
- }
-
- free(lookup);
- } else {
- #if defined(DITHER2) || defined(DITHER4)
- slong i, j, r_pix, g_pix, b_pix, offset, dir, two_val,
- odd_scanline = 0, err_len = (width + 2) * 3;
- uchar *range_tbl = malloc(3 * 256), *range = range_tbl + 256;
- sshort *lookup = malloc(sizeof(short) * 32768),
- *erowerr = malloc(sizeof(short) * err_len),
- *orowerr = malloc(sizeof(short) * err_len),
- *thisrowerr, *nextrowerr;
- schar *dith_max_tbl = malloc(512), *dith_max = dith_max_tbl + 256;
-
-
-
-
- if (range_tbl == NULL || lookup == NULL ||
- erowerr == NULL || orowerr == NULL || dith_max_tbl == NULL) {
- if (range_tbl != NULL)
- free(range_tbl);
- if (lookup != NULL)
- free(lookup);
- if (erowerr != NULL)
- free(erowerr);
- if (orowerr != NULL)
- free(orowerr);
- if (dith_max_tbl != NULL)
- free(dith_max_tbl);
- return 0;
- }
-
- for (i = 0; i < err_len; i++)
- erowerr[i] = 0;
-
- for (i = 0; i < 32768; i++)
- lookup[i] = -1;
-
- for (i = 0; i < 256; i++) {
- range_tbl[i] = 0;
- range_tbl[i + 256] = (uchar) i;
- range_tbl[i + 512] = 255;
- }
-
- for (i = 0; i < 256; i++) {
- dith_max_tbl[i] = -DITHER_MAX;
- dith_max_tbl[i + 256] = DITHER_MAX;
- }
- for (i = -DITHER_MAX; i <= DITHER_MAX; i++)
- dith_max_tbl[i + 256] = i;
-
- for (i = 0 ; i < height; i++) {
- if (odd_scanline) {
- dir = -1;
- in += (width - 1) * 4;
- out += (width - 1);
- thisrowerr = orowerr + 3;
- nextrowerr = erowerr + width * 3;
- } else {
- dir = 1;
- thisrowerr = erowerr + 3;
- nextrowerr = orowerr + width * 3;
- }
- nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
- for (j = 0; j < width; j++) {
- #ifdef DITHER2
- r_pix = range[(thisrowerr[0] >> 1) + in[0]];
- g_pix = range[(thisrowerr[1] >> 1) + in[1]];
- b_pix = range[(thisrowerr[2] >> 1) + in[2]];
- #else
- r_pix = range[((thisrowerr[0] + 8) >> 4) + in[0]];
- g_pix = range[((thisrowerr[1] + 8) >> 4) + in[1]];
- b_pix = range[((thisrowerr[2] + 8) >> 4) + in[2]];
- #endif
- offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
- if (lookup[offset] < 0)
- lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
- *out = lookup[offset]+base;
- r_pix = dith_max[r_pix - palette[0][lookup[offset]]];
- g_pix = dith_max[g_pix - palette[1][lookup[offset]]];
- b_pix = dith_max[b_pix - palette[2][lookup[offset]]];
- #ifdef DITHER2
- nextrowerr[0 ] = r_pix;
- thisrowerr[0+3] += r_pix;
- nextrowerr[1 ] = g_pix;
- thisrowerr[1+3] += g_pix;
- nextrowerr[2 ] = b_pix;
- thisrowerr[2+3] += b_pix;
- #else
- two_val = r_pix * 2;
- nextrowerr[0-3] = r_pix;
- r_pix += two_val;
- nextrowerr[0+3] += r_pix;
- r_pix += two_val;
- nextrowerr[0 ] += r_pix;
- r_pix += two_val;
- thisrowerr[0+3] += r_pix;
- two_val = g_pix * 2;
- nextrowerr[1-3] = g_pix;
- g_pix += two_val;
- nextrowerr[1+3] += g_pix;
- g_pix += two_val;
- nextrowerr[1 ] += g_pix;
- g_pix += two_val;
- thisrowerr[1+3] += g_pix;
- two_val = b_pix * 2;
- nextrowerr[2-3] = b_pix;
- b_pix += two_val;
- nextrowerr[2+3] += b_pix;
- b_pix += two_val;
- nextrowerr[2 ] += b_pix;
- b_pix += two_val;
- thisrowerr[2+3] += b_pix;
- #endif
- thisrowerr += 3;
- nextrowerr -= 3;
- in += dir * 4;
- out += dir;
- }
- if ((i % 2) == 1) {
- in += (width + 1) * 4;
- out += (width + 1);
- }
- odd_scanline = !odd_scanline;
- }
-
- free(range_tbl);
- free(lookup);
- free(erowerr);
- free(orowerr);
- free(dith_max_tbl);
- #else
- slong i, j, r_pix, g_pix, b_pix, r_err, g_err, b_err, offset;
- uchar *range_tbl = malloc(3 * 256), *range = range_tbl + 256;
- sshort *lookup = malloc(sizeof(short) * 32768);
-
- if (range_tbl == NULL || lookup == NULL) {
- if (range_tbl != NULL)
- free(range_tbl);
- if (lookup != NULL)
- free(lookup);
- return 0;
- }
-
- for (i = 0; i < 32768; i++)
- lookup[i] = -1;
-
- for (i = 0; i < 256; i++) {
- range_tbl[i] = 0;
- range_tbl[i + 256] = (uchar) i;
- range_tbl[i + 512] = 255;
- }
-
- for (i = 0; i < height; i++) {
- r_err = g_err = b_err = 0;
- for (j = width - 1; j >= 0; j--) {
- r_pix = range[(r_err >> 1) + in[0]];
- g_pix = range[(g_err >> 1) + in[1]];
- b_pix = range[(b_err >> 1) + in[2]];
- offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
- if (lookup[offset] < 0)
- lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
- *out++ = lookup[offset]+base;
- r_err = r_pix - palette[0][lookup[offset]];
- g_err = g_pix - palette[1][lookup[offset]];
- b_err = b_pix - palette[2][lookup[offset]];
- in += 4;
- }
- }
-
-
-
- free(range_tbl);
- free(lookup);
- #endif
- }
- return 1;
- }
-
- LOCAL int
- bestcolor(int r, int g, int b) {
- ulong i, bestcolor, curdist, mindist;
- slong rdist, gdist, bdist;
-
- r = (r & 248) + 4;
- g = (g & 248) + 4;
- b = (b & 248) + 4;
- mindist = 200000;
- for (i = 0; i < tot_colors; i++) {
- rdist = palette[0][i] - r;
- gdist = palette[1][i] - g;
- bdist = palette[2][i] - b;
- curdist = squares[rdist] + squares[gdist] + squares[bdist];
- if (curdist < mindist) {
- mindist = curdist;
- bestcolor = i;
- }
- }
- return (int)bestcolor;
- }
-